package ynu.lcy.elememicroservicegateway.filter;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.Claims;
import com.alibaba.nacos.api.remote.response.ErrorResponse;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import ynu.lcy.elememicroservicecommon.enums.UserRoleEnum;
import ynu.lcy.elememicroservicecommon.utils.BaseResponse;
import ynu.lcy.elememicroservicecommon.utils.ErrorCode;
import ynu.lcy.elememicroservicegateway.config.BlackListConfig;
import ynu.lcy.elememicroservicegateway.utils.CommonUtils;

import java.nio.charset.StandardCharsets;
import java.util.List;


@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Autowired
    private BlackListConfig blackListConfig;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest serverHttpRequest = exchange.getRequest();
        String path = serverHttpRequest.getURI().getPath();

        //放行接口文档
        if(antPathMatcher.match("/**/v2/api-docs/**", path)){
            return  chain.filter(exchange);
        }
        // 判断路径中是否包含 inner，只允许内部调用
        if (antPathMatcher.match("/**/inner/**", path)) {
            return CommonUtils.buildErrorResponse(exchange.getResponse(),
                    HttpStatus.FORBIDDEN, ErrorCode.NO_AUTH_ERROR);
        }

        // 黑名单校验、认证和授权逻辑,不做有效性和时效性，只做判断是否存在token
        // 这里只做黑名单校验，不做token校验，因为token的有效期和时效性由各个微服务自己控制，这里不做控制
        List<String> paths = blackListConfig.getPaths();
        String authToken = CommonUtils.extractToken(serverHttpRequest);
        for (String blackListPath : paths) {
            if (antPathMatcher.match(blackListPath, path)) {
                // 检查是否有 token
                if (authToken == null) {
                    return CommonUtils.buildErrorResponse(exchange.getResponse(),
                            HttpStatus.UNAUTHORIZED, ErrorCode.NOT_LOGIN_ERROR);
                }
                //校验
                DecodedJWT decodedJWT = CommonUtils.validateToken(authToken);
                if (ObjectUtil.isNull(decodedJWT)) {
                    return CommonUtils.buildErrorResponse(exchange.getResponse(),
                            HttpStatus.UNAUTHORIZED, ErrorCode.TOKEN_ERROR);
                }
                // 解码 token，获取用户角色信息
                String role = decodedJWT.getClaim("role").asString();

                // 检查是否有权限访问该路径
                if (path.contains("/admin/") && !role.equals(UserRoleEnum.ADMIN.getValue())) {
                    return CommonUtils.buildErrorResponse(exchange.getResponse(),
                            HttpStatus.FORBIDDEN, ErrorCode.NO_AUTH_ERROR);
                }
            }
        }
        // 放行
        return chain.filter(exchange);
    }
    /**
     * 优先级提到最高
     * @return
     */
    @Override
    public int getOrder() {
        return 1;
    }
}

